/*
	This file is part of Posixcpp library.

	Posixcpp library is free software: you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public License
	as published by the Free Software Foundation, either version 3 of
	the License, or (at your option) any later version.

	Posixcpp library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU LesserGeneral Public
	License along with Posixcpp library. If not, see
	<http://www.gnu.org/licenses/>.
 */

#ifndef BOUNDEDSYNCHRONIZEDQUEUE_HPP
#define	BOUNDEDSYNCHRONIZEDQUEUE_HPP

#include "posix_threads_condition.hpp"
#include "posixcpp_containers_ringbuffer.hpp"

namespace posixcpp
{
namespace containers
{
template< typename Element_Type, size_t Default_Capacity >
class BoundedSynchronizedQueue
{
public:
	BoundedSynchronizedQueue( size_t Capacity = Default_Capacity ) :
	m_capacity(Capacity),
	m_list(Capacity),
	m_fullCondition(m_lock),
	m_emptyCondition(m_lock)
	{
		PRECONDITION_ASSERT( Default_Capacity > 0, "Default_Capacity should be positive" );
		PRECONDITION_ASSERT( Capacity > 0, "Capacity should be positive" );
	}
	~BoundedSynchronizedQueue()
	{
	}
	void enqueue( Element_Type New_Item )
	{
		posix::threads::CriticalSection cs(m_lock);

		while (m_list.length() >= m_capacity)
			m_fullCondition.wait();

		m_list.enqueue(New_Item);
		if (m_list.length() == 1)
			m_emptyCondition.broadcast();
	}
	void dequeue( Element_Type & Element )
	{
		posix::threads::CriticalSection cs(m_lock);

		while (m_list.length() == 0)
			m_emptyCondition.wait();

		m_list.dequeue(Element);
		if ( m_list.length() == m_list.maxLength() - 1 )
			m_fullCondition.broadcast();
	}
	size_t Current_Use()
	{
		return m_list.length();
	}
	size_t Peak_Use()
	{
		return m_list.maxLength();
	}
private:
	const size_t m_capacity;
	RingBuffer<Element_Type> m_list;
	posix::threads::Mutex m_lock;
	posix::threads::Condition m_fullCondition;
	posix::threads::Condition m_emptyCondition;
};
}
}

#endif	/* BOUNDEDSYNCHRONIZEDQUEUE_HPP */
